{
  "nbformat": 4,
  "nbformat_minor": 0,
  "metadata": {
    "colab": {
      "name": "GEN_1_regression_pytorch.ipynb",
      "provenance": [],
      "authorship_tag": "ABX9TyNbc0XTURgM2wOqSemE9tSw",
      "include_colab_link": true
    },
    "kernelspec": {
      "name": "python3",
      "display_name": "Python 3"
    }
  },
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "view-in-github",
        "colab_type": "text"
      },
      "source": [
        "<a href=\"https://colab.research.google.com/github/cxbxmxcx/GenReality/blob/master/GEN_1_regression_pytorch.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "XhB46Q8JTpBd"
      },
      "source": [
        "from sklearn.datasets import load_boston\n",
        "from sklearn.model_selection import train_test_split\n",
        "\n",
        "import numpy  as np\n",
        "import matplotlib.pyplot as plt\n",
        "\n",
        "import torch\n",
        "import torch.nn as nn\n",
        "\n",
        "import pandas as pd"
      ],
      "execution_count": 1,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "tNHQgiXUUFIa"
      },
      "source": [
        "boston = load_boston()\n",
        "X,y   = (boston.data, boston.target)\n",
        "boston.data[:2]\n",
        "inputs = X.shape[1]"
      ],
      "execution_count": 2,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "hXpiGQHDuKWl",
        "outputId": "d43378f4-5b79-4f60-fb97-2a697c4cbf31"
      },
      "source": [
        "bos = pd.DataFrame(boston.data)\n",
        "print(bos.head())"
      ],
      "execution_count": 3,
      "outputs": [
        {
          "output_type": "stream",
          "text": [
            "        0     1     2    3      4   ...   8      9     10      11    12\n",
            "0  0.00632  18.0  2.31  0.0  0.538  ...  1.0  296.0  15.3  396.90  4.98\n",
            "1  0.02731   0.0  7.07  0.0  0.469  ...  2.0  242.0  17.8  396.90  9.14\n",
            "2  0.02729   0.0  7.07  0.0  0.469  ...  2.0  242.0  17.8  392.83  4.03\n",
            "3  0.03237   0.0  2.18  0.0  0.458  ...  3.0  222.0  18.7  394.63  2.94\n",
            "4  0.06905   0.0  2.18  0.0  0.458  ...  3.0  222.0  18.7  396.90  5.33\n",
            "\n",
            "[5 rows x 13 columns]\n"
          ],
          "name": "stdout"
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "z05ZyUrmU7is",
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "outputId": "9bb6d5dd-fb86-41df-ab35-931e9f96398f"
      },
      "source": [
        "X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=0)\n",
        "num_train = X_train.shape[0]\n",
        "X_train[:2], y_train[:2]\n",
        "num_train"
      ],
      "execution_count": 4,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "404"
            ]
          },
          "metadata": {
            "tags": []
          },
          "execution_count": 4
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "QLshQolGVUlz"
      },
      "source": [
        "torch.set_default_dtype(torch.float64)\n",
        "net = nn.Sequential(\n",
        "    nn.Linear(inputs, 50, bias = True), nn.ReLU(),\n",
        "    nn.Linear(50, 50, bias = True), nn.ReLU(),\n",
        "    nn.Linear(50, 50, bias = True), nn.Sigmoid(),\n",
        "    nn.Linear(50, 1)\n",
        ")\n",
        "loss_fn = nn.MSELoss()\n",
        "optimizer = torch.optim.Adam(net.parameters(), lr = .001)"
      ],
      "execution_count": 5,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "ZhR9h8Y3WCWM"
      },
      "source": [
        "num_epochs = 8000\n",
        "y_train_t = torch.from_numpy(y_train).clone().reshape(-1, 1)\n",
        "x_train_t = torch.from_numpy(X_train).clone()\n",
        "y_test_t = torch.from_numpy(y_test).clone().reshape(-1, 1)\n",
        "x_test_t = torch.from_numpy(X_test).clone()\n",
        "history = []"
      ],
      "execution_count": 6,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "Ef62jrN3WP0d",
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "outputId": "1041e6bd-7d72-47f1-da31-e0d8c263084a"
      },
      "source": [
        "for i in range(num_epochs):\n",
        "    y_pred = net(x_train_t)\n",
        "    loss = loss_fn(y_train_t,y_pred)\n",
        "    history.append(loss.data)    \n",
        "    loss.backward()\n",
        "    optimizer.step()\n",
        "    optimizer.zero_grad()  \n",
        "    test_loss = loss_fn(y_test_t,net(x_test_t))  \n",
        "    if i > 0 and i % 100 == 0:\n",
        "        print(f'Epoch {i}, loss = {loss:.3f}, test loss {test_loss:.3f}')"
      ],
      "execution_count": 7,
      "outputs": [
        {
          "output_type": "stream",
          "text": [
            "Epoch 100, loss = 361.638, test loss 343.932\n",
            "Epoch 200, loss = 266.500, test loss 251.602\n",
            "Epoch 300, loss = 199.701, test loss 187.212\n",
            "Epoch 400, loss = 154.283, test loss 143.850\n",
            "Epoch 500, loss = 124.788, test loss 116.070\n",
            "Epoch 600, loss = 103.971, test loss 99.296\n",
            "Epoch 700, loss = 84.527, test loss 83.124\n",
            "Epoch 800, loss = 70.453, test loss 73.640\n",
            "Epoch 900, loss = 61.279, test loss 66.028\n",
            "Epoch 1000, loss = 54.815, test loss 61.762\n",
            "Epoch 1100, loss = 49.963, test loss 57.453\n",
            "Epoch 1200, loss = 44.407, test loss 53.828\n",
            "Epoch 1300, loss = 38.060, test loss 47.988\n",
            "Epoch 1400, loss = 33.572, test loss 44.470\n",
            "Epoch 1500, loss = 30.324, test loss 44.872\n",
            "Epoch 1600, loss = 26.943, test loss 40.902\n",
            "Epoch 1700, loss = 24.669, test loss 39.671\n",
            "Epoch 1800, loss = 22.695, test loss 39.206\n",
            "Epoch 1900, loss = 20.979, test loss 37.579\n",
            "Epoch 2000, loss = 19.474, test loss 37.252\n",
            "Epoch 2100, loss = 17.688, test loss 36.072\n",
            "Epoch 2200, loss = 16.643, test loss 34.744\n",
            "Epoch 2300, loss = 15.765, test loss 34.074\n",
            "Epoch 2400, loss = 14.716, test loss 33.279\n",
            "Epoch 2500, loss = 13.187, test loss 32.956\n",
            "Epoch 2600, loss = 12.333, test loss 31.663\n",
            "Epoch 2700, loss = 11.443, test loss 32.494\n",
            "Epoch 2800, loss = 10.785, test loss 30.797\n",
            "Epoch 2900, loss = 10.026, test loss 31.195\n",
            "Epoch 3000, loss = 9.385, test loss 30.109\n",
            "Epoch 3100, loss = 8.866, test loss 30.111\n",
            "Epoch 3200, loss = 8.426, test loss 31.332\n",
            "Epoch 3300, loss = 7.947, test loss 30.592\n",
            "Epoch 3400, loss = 7.387, test loss 30.816\n",
            "Epoch 3500, loss = 7.153, test loss 30.549\n",
            "Epoch 3600, loss = 6.568, test loss 30.285\n",
            "Epoch 3700, loss = 6.333, test loss 30.197\n",
            "Epoch 3800, loss = 5.675, test loss 29.454\n",
            "Epoch 3900, loss = 5.503, test loss 29.092\n",
            "Epoch 4000, loss = 5.010, test loss 28.550\n",
            "Epoch 4100, loss = 4.868, test loss 28.340\n",
            "Epoch 4200, loss = 4.570, test loss 28.373\n",
            "Epoch 4300, loss = 4.334, test loss 27.917\n",
            "Epoch 4400, loss = 4.082, test loss 28.089\n",
            "Epoch 4500, loss = 3.829, test loss 27.707\n",
            "Epoch 4600, loss = 3.698, test loss 27.947\n",
            "Epoch 4700, loss = 3.486, test loss 28.132\n",
            "Epoch 4800, loss = 3.359, test loss 28.242\n",
            "Epoch 4900, loss = 3.199, test loss 27.727\n",
            "Epoch 5000, loss = 3.142, test loss 27.894\n",
            "Epoch 5100, loss = 2.999, test loss 27.760\n",
            "Epoch 5200, loss = 2.884, test loss 27.655\n",
            "Epoch 5300, loss = 2.798, test loss 28.010\n",
            "Epoch 5400, loss = 2.955, test loss 27.524\n",
            "Epoch 5500, loss = 2.638, test loss 27.920\n",
            "Epoch 5600, loss = 2.652, test loss 27.624\n",
            "Epoch 5700, loss = 2.639, test loss 27.399\n",
            "Epoch 5800, loss = 2.527, test loss 27.359\n",
            "Epoch 5900, loss = 2.770, test loss 28.731\n",
            "Epoch 6000, loss = 2.232, test loss 27.967\n",
            "Epoch 6100, loss = 2.159, test loss 27.610\n",
            "Epoch 6200, loss = 2.066, test loss 27.186\n",
            "Epoch 6300, loss = 2.051, test loss 26.501\n",
            "Epoch 6400, loss = 2.034, test loss 26.526\n",
            "Epoch 6500, loss = 1.862, test loss 27.168\n",
            "Epoch 6600, loss = 1.813, test loss 26.657\n",
            "Epoch 6700, loss = 1.854, test loss 25.780\n",
            "Epoch 6800, loss = 1.766, test loss 26.558\n",
            "Epoch 6900, loss = 1.708, test loss 25.562\n",
            "Epoch 7000, loss = 1.636, test loss 26.050\n",
            "Epoch 7100, loss = 1.604, test loss 25.381\n",
            "Epoch 7200, loss = 1.613, test loss 25.960\n",
            "Epoch 7300, loss = 1.549, test loss 25.285\n",
            "Epoch 7400, loss = 1.542, test loss 25.706\n",
            "Epoch 7500, loss = 1.507, test loss 25.314\n",
            "Epoch 7600, loss = 1.488, test loss 25.299\n",
            "Epoch 7700, loss = 1.475, test loss 25.073\n",
            "Epoch 7800, loss = 1.545, test loss 25.071\n",
            "Epoch 7900, loss = 1.528, test loss 25.537\n"
          ],
          "name": "stdout"
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "IifIajH-XFrl",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 282
        },
        "outputId": "eba9afba-c41c-4a14-cf87-85ad0f596572"
      },
      "source": [
        "plt.plot(history)"
      ],
      "execution_count": 8,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "[<matplotlib.lines.Line2D at 0x7f6ab0f678d0>]"
            ]
          },
          "metadata": {
            "tags": []
          },
          "execution_count": 8
        },
        {
          "output_type": "display_data",
          "data": {
            "image/png": "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\n",
            "text/plain": [
              "<Figure size 432x288 with 1 Axes>"
            ]
          },
          "metadata": {
            "tags": [],
            "needs_background": "light"
          }
        }
      ]
    }
  ]
}